//
// Created by myrica on 2/17/25.
//

#ifndef ASTEXPRESSION_H
#define ASTEXPRESSION_H

#include <utility>

#include "ASTBase.h"


namespace ast {
    struct ExpressionPrimary final : Expression {
        // expression literal literal symbol
        using primary_t = std::variant<Expression *, int, float, std::string>;

        primary_t value;

        explicit ExpressionPrimary(primary_t value) : Expression(Primary), value(std::move(value)) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Primary;
        }
    };

    struct ExpressionUnary final : Expression {
        Expression *exp;
        // assume PlusPlus and MinusMinus only appear once at most
        vector<ASTOperator> ops;

        ExpressionUnary(Expression *exp, const vector<ASTOperator> &ops) : Expression(Unary), exp(exp), ops(ops) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Unary;
        }
    };

    struct ExpressionCast final : Expression {
        Expression *exp;
        type::ASTType type;

        ExpressionCast(Expression *exp, type::ASTType type) : Expression(Cast), exp(exp), type(type) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Cast;
        }
    };

    struct ExpressionMultiplicative final : Expression {
        Expression *base;

        vector<pair<ASTOperator, Expression *> > others;

        ExpressionMultiplicative(Expression *base,
                                 const vector<pair<ASTOperator, Expression *> > &others) : Expression(Multiplicative),
            base(base), others(others) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Multiplicative;
        }
    };

    struct ExpressionAdditive final : Expression {
        Expression *base;

        vector<pair<ASTOperator, Expression *> > others;

        ExpressionAdditive(Expression *base,
                           const vector<pair<ASTOperator, Expression *> > &others) : Expression(Additive),
            base(base), others(others) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Additive;
        }
    };

    struct ExpressionShift final : Expression {
        Expression *base;

        vector<pair<ASTOperator, Expression *> > others;

        ExpressionShift(Expression *base,
                        const vector<pair<ASTOperator, Expression *> > &others) : Expression(Shift),
            base(base), others(others) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Shift;
        }
    };

    struct ExpressionRelational final : Expression {
        Expression *base;

        vector<pair<ASTOperator, Expression *> > others;

        ExpressionRelational(Expression *base,
                             const vector<pair<ASTOperator, Expression *> > &others) : Expression(Relational),
            base(base), others(others) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Relational;
        }
    };

    struct ExpressionEquality final : Expression {
        Expression *base;

        vector<pair<ASTOperator, Expression *> > others;

        ExpressionEquality(Expression *base,
                           const vector<pair<ASTOperator, Expression *> > &others) : Expression(Equality),
            base(base), others(others) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Equality;
        }
    };

    struct ExpressionAnd final : Expression {
        vector<Expression *> exps;

        explicit ExpressionAnd(const vector<Expression *> &exps) : Expression(And), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == And;
        }
    };

    struct ExpressionExclusiveOr final : Expression {
        vector<Expression *> exps;

        explicit ExpressionExclusiveOr(const vector<Expression *> &exps) : Expression(ExclusiveOr), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == ExclusiveOr;
        }
    };

    struct ExpressionInclusiveOr final : Expression {
        vector<Expression *> exps;

        explicit ExpressionInclusiveOr(const vector<Expression *> &exps) : Expression(InclusiveOr), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == InclusiveOr;
        }
    };

    struct ExpressionLogicalAnd final : Expression {
        vector<Expression *> exps;

        explicit ExpressionLogicalAnd(const vector<Expression *> &exps) : Expression(LogicalAnd), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == LogicalAnd;
        }
    };

    struct ExpressionLogicalOr final : Expression {
        vector<Expression *> exps;

        explicit ExpressionLogicalOr(const vector<Expression *> &exps) : Expression(LogicalOr), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == LogicalOr;
        }
    };

    struct ExpressionConditional final : Expression {
        Expression *cond;
        Expression *former;
        Expression *latter;

        ExpressionConditional(Expression *cond, Expression *former, Expression *latter) : Expression(Conditional),
            cond(cond),
            former(former),
            latter(latter) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Conditional;
        }
    };

    struct ExpressionAssignment final : Expression {
        Expression *base;
        // vector<pair<ASTOperator, Expression *> > others;
        //
        // ExpressionAssignment(Expression *base,
        //                      const vector<pair<ASTOperator, Expression *> > &others) : Expression(Assignment),
        //     base(base), others(others) {
        // }

        optional<pair<ASTOperator, Expression *> > assignment;

        ExpressionAssignment(Expression *base,
                             optional<pair<ASTOperator, Expression *> > assignment) : Expression(Assignment),
            base(base), assignment(
                std::move(assignment)) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Assignment;
        }
    };

    struct ExpressionInitializerList final : Expression {
        vector<Expression *> exps;

        explicit ExpressionInitializerList(const vector<Expression *> &exps) : Expression(InitializerList), exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == InitializerList;
        }
    };

    struct ExpressionPostfix final : Expression {
        ExpressionPrimary *primary;
        ASTOperator op;
        vector<Expression *> exps;

        ExpressionPostfix(ExpressionPrimary *primary, ASTOperator op,
                          const vector<Expression *> &exps) : Expression(Postfix), primary(primary), op(op),
                                                              exps(exps) {
        }

        static bool classof(const ASTBase *exp) {
            return exp->getKind() == Postfix;
        }
    };
}

#endif //ASTEXPRESSION_H
